﻿using System;
using DimensionsHelper.Common.Contracts.Services;

namespace DimensionsHelper.Common.Contracts.Metadata;

/// <summary>
///     序列化器进行序列化和反序列化时的文本类型：
///     <list type="number">
///         <item>Xml - 文本是Xml文档</item>
///         <item>Script - 文本是DMS脚本</item>
///     </list>
/// </summary>
public enum MetadataSerializerKind
{
    /// <summary>
    ///     输入或输出的文本是XML格式。
    /// </summary>
    Xml,

    /// <summary>
    ///     输入或输出的文本是DMS脚本格式。
    /// </summary>
    Script
}


/// <summary>
///     指示在序列化成脚本（<see cref="MetadataSerializerKind.Script" />）时，
///     保留的细则元素类型。
/// </summary>
[Flags]
public enum MetadataElementFlags
{
    /// <summary>
    ///     不保留所有细则
    /// </summary>
    None = 0,

    /// <summary>
    ///     保留 properties
    /// </summary>
    Properties = 0x1,

    /// <summary>
    ///     保留 templates
    /// </summary>
    Templates = 0x2,

    /// <summary>
    ///     保留 style
    /// </summary>
    Styles = 0x4,

    /// <summary>
    ///     保留 labelstyle
    /// </summary>
    LabelStyles = 0x8,

    /// <summary>
    ///     保留注释
    /// </summary>
    Notes = 0x10,

    /// <summary>
    ///     保留文档级别HData属性
    /// </summary>
    HData = 0x20,

    /// <summary>
    ///     保留所有细则元素
    /// </summary>
    All = Properties | Templates | Styles | LabelStyles | Notes | HData
}


/// <summary>
///     元数据序列化时
/// </summary>
public class MetadataSerializeOptions
{
    /// <summary>
    ///     序列化元数据文档到脚本时是否忽略Metadata() Section。
    /// </summary>
    public bool IgnoreMetadataSection = false;

    /// <summary>
    ///     指示读取或输出的文本类型
    /// </summary>
    public MetadataSerializerKind Kind { get; set; } = MetadataSerializerKind.Xml;

    /// <summary>
    ///     指示序列化DMS脚本时的缩进空格数，只有在序列化并且<see cref="Kind" />值是<see cref="MetadataSerializerKind.Script" />时才有用。
    /// </summary>
    public int Indent { get; set; }

    /// <summary>
    ///     指示序列化DMS脚本时，保留的属性细则元素类型 - properties、templates、styles、labelstyles、notes。默认是<see cref="MetadataElementFlags.All" />
    /// </summary>
    public MetadataElementFlags ElementFlags { get; set; } = MetadataElementFlags.All;

    /// <summary>
    ///     获取或设置序列化DMS脚本时，使用的上下文类型。如果使用文档默认上下文类型，设置此值为null。默认是null。
    /// </summary>
    public string? Context { get; set; }

    /// <summary>
    ///     获取或设置序列化DMS脚本时，使用的语言类型。如果使用文档默认的语言类型，设置此值为null或<see cref="string.Empty" />。默认是null。
    /// </summary>
    public string? Language { get; set; }

    /// <summary>
    ///     获取或设置序列化DMS脚本时，使用的标签类型。如果使用文档默认的标签类型，设置此值为null。默认是null。
    /// </summary>
    public string? LabelType { get; set; }

    /// <summary>
    ///     需要报告信息或抛出错误时的接管对象，如果此值是null，遇到错误时将通过throw抛出。
    /// </summary>
    public IReportService? ReportService { get; set; }

    /// <summary>
    ///     判断<see cref="ElementFlags" />是否包含了给定的元素类型Flag。
    /// </summary>
    /// <param name="flags">需要检查的元素类型</param>
    /// <returns></returns>
    public bool HasMetadataElementFlag(MetadataElementFlags flags)
    {
        return (ElementFlags & flags) != 0;
    }
}


/// <summary>
///     元数据文档的序列化器，支持序列化和反序列化<see cref="IMetadataDocument" />类型的文档。
/// </summary>
public interface IMetadataSerializer
{
    /// <summary>
    ///     获取或设置序列化器的配置。
    /// </summary>
    MetadataSerializeOptions Options { get; set; }

    /// <summary>
    ///     读取指定的路径的文件，并使用<see cref="Options" />的配置创建<see cref="IMetadataDocument" />类型的对象。
    /// </summary>
    /// <param name="fileName">指定文件路径</param>
    /// <returns>反序列化后的对象</returns>
    IMetadataDocument Deserialize(string fileName);

    /// <summary>
    ///     向已有的Metadata文档中填入指定文件的内容。
    /// </summary>
    /// <param name="fileName">指定文件路径</param>
    /// <param name="document">已有的元数据对象</param>
    /// <remarks>
    ///     如果给定的文档对象不是空，具体处理应当由实现类决定。
    /// </remarks>
    void Deserialize(string fileName, IMetadataDocument document);

    /// <summary>
    ///     使用<see cref="Options" />的配置，将<see cref="IMetadataDocument" />类型的对象序列化成字符串。
    /// </summary>
    /// <param name="document">已有的Metadata文档</param>
    /// <returns>Xml或Script格式的字符串</returns>
    string Serialize(IMetadataDocument document);
}